﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Configuration;
using Microsoft.SharePoint;
using System.Collections;
using System.IO;
using Microsoft.SharePoint.Administration;

namespace SharePoint.SPSilver
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        
        SPWeb _web = null;
        SPSite _site = null;
        List<ClassIngredients> classList = new List<ClassIngredients>();
        public MainWindow()
        {
            InitializeComponent();
            textBlockCode.Text = String.Empty;
        }
        private void Window_Unloaded(object sender, RoutedEventArgs e)
        {
            if (_site!= null)
                _site.Dispose();
            if (_web!= null)
                _web.Dispose();

        }
        private void sitesBox_Loaded(object sender, RoutedEventArgs e)
        {
            if (ConfigurationManager.AppSettings["Sites"] == null)
            { 
                SPFarm farm = SPFarm.Local;
                SPWebService service = farm.Services.GetValue<SPWebService>("");
                foreach (SPWebApplication webApp in service.WebApplications)
                {
                    // webApp.
                    if (webApp.Sites.Count > 0)
                    {
                        foreach (SPSite s in webApp.Sites)
                        {
                            listBoxSites.Items.Add(s.Url);
                        }
                    }
                }
            
            }
            else
            {
                String sitesJoined = ConfigurationManager.AppSettings["Sites"].ToString();
                String[] sites = sitesJoined.Split(new char[]{','},StringSplitOptions.RemoveEmptyEntries);
                for (int i = 0; i < sites.Length; i++)
                {
                    if (sites[i]!= null)
                        listBoxSites.Items.Add(sites[i]);
                }
                listBoxSites.IsEnabled = true;
            }
        }

        private void OpenSitesBtn_Click(object sender, RoutedEventArgs e)
        {
            /// save settings
            {
                List<string> sites = new List<string>();
                foreach (Object o in listBoxSites.Items)
                {
                    if (!String.IsNullOrEmpty(o.ToString()))
                        sites.Add(o.ToString());
                }
                if (!sites.Contains(listBoxSites.Text))
                    if (!String.IsNullOrEmpty(listBoxSites.Text))
                        sites.Add(listBoxSites.Text);
                String[] sitesArray = (sites.ToArray());
                String sitesJoined = String.Join(",", sitesArray);
                System.Configuration.Configuration config =
                    ConfigurationManager.OpenExeConfiguration(
                          ConfigurationUserLevel.None);
                if (!config.AppSettings.Settings.AllKeys.Contains("Sites"))
                    config.AppSettings.Settings.Add("Sites", sitesJoined);
                else
                {
                    config.AppSettings.Settings["Sites"].Value = sitesJoined;
                }

                // Save the configuration file.
                config.Save(ConfigurationSaveMode.Modified);
                ConfigurationManager.RefreshSection("appSettings");
            }
            /// load web sites
            { 
                //using (SPSite site = new SPSite(sitesBox.Text))
                if (_site!=null)
                    _site.Dispose();
                _site = new SPSite(listBoxSites.Text);
                {
                    // websBox.ItemsSource = site.AllWebs.Names;
                    listBoxWebs.Items.Clear();
                    listBoxWebs.IsEnabled = true;
                    if (_site != null)
                    {
                        foreach (SPWeb web in _site.AllWebs)
                        {
                            // listBoxWebs.Items.Add(web);
                            listBoxWebs.Items.Add(web.ServerRelativeUrl);
                            web.Dispose();
                        }
                    }
                }
            }
        }

        private void listBoxWebs_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (!isHandlersEnabled && (sender !=null && e!=null)) return;
            // using (SPSite site = new SPSite(sitesBox.Text))
            {
                // using (SPWeb web = site.OpenWeb(websBox.SelectedValue.ToString(),false))
                if (_web != null)
                    _web.Dispose();
                if ((listBoxWebs.SelectedValue)!=null)
                    if (!String.IsNullOrEmpty(listBoxWebs.SelectedValue.ToString()))
                    {
                        _web = // (SPWeb)listBoxWebs.SelectedValue;
                            _site.OpenWeb(listBoxWebs.SelectedValue.ToString());
                        listBoxLists.Items.Clear();
                        listBoxLists.IsEnabled = true;
                        {
                            if (_web != null)
                            {
                                foreach (SPList list in _web.Lists)
                                {
                                    listBoxLists.Items.Add(list);
                                }
                            }
                        }
                    }
            }
        }

        private void listBoxLists_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (!isHandlersEnabled && (sender != null && e != null)) return;
            // using (SPSite site = new SPSite(sitesBox.Text))
            {
                // using (SPWeb web = site.OpenWeb(websBox.SelectedValue.ToString(),false))
                {
                    // SPList list = _web.GetListFromUrl(listsBox1.SelectedValue.ToString());
                    /*((Grid)Fields.Content).Children.Clear();*/
                    listBoxContentTypes.Items.Clear();
                    listBoxContentTypes.IsEnabled = true;
                    
                    SPList list = (SPList)listBoxLists.SelectedValue;
                    if (list != null)
                    {
                        foreach (SPContentType type in list.ContentTypes)
                        {
                            listBoxContentTypes.Items.Add(new ContentType(type));
                        }
                    }
                }
            }
        }
        private void listBoxContentTypes_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (!isHandlersEnabled && (sender != null && e != null)) return;
            listBoxFields.Items.Clear();
            listBoxFields.IsEnabled = true;
            if (listBoxContentTypes.SelectedValue != null)
            {
                ContentType type = (ContentType)listBoxContentTypes.SelectedValue;
                textBoxContentTypeName.Text = type.Name;
                textBoxContentTypeName.IsEnabled = true;
                textBoxNamespaceName.IsEnabled = true;
                listBoxFields.DisplayMemberPath = "Combined_DisplayName";
                foreach (SPField field in type.Fields)
                {
                    if (field.ReadOnlyField || (field.Hidden && field.Sealed)
                        // || field.
                        )
                    {
                        // do nothing
                    }
                    else
                    {
                        int i = listBoxFields.Items.Add(new SPField_Extended(field));
                    }
                }
            }
        }
        private void Generate_Click(object sender, RoutedEventArgs e)
        { 
            if (listBoxNewClasses.SelectedItems.Count == 0)
            {
                MessageBox.Show("Please select the content types you wish to generate",
                                "No content types were selected",
                                MessageBoxButton.OK);
                return;
            }

            StringBuilder sb = new StringBuilder();
            String folder = DateTime.Now.ToString("yyyy.MM.dd - HH.mm");
            DirectoryInfo dirInfo = Directory.CreateDirectory(folder);
            textBlockCode.Text += String.Format("Created folder {0}: {1}\n",folder,dirInfo.FullName);
            List<String> classLists = new List<string>();
            Boolean includeListDefinition  = true;
            classLists.Clear();
            foreach (ClassIngredients ingredients in listBoxNewClasses.SelectedItems)
            {
                
                includeListDefinition = (!classLists.Contains(ingredients.listClassName));
                if (includeListDefinition) classLists.Add(ingredients.listClassName);
                sb.Append((ingredients.buildClassCode(classList, checkBoxIsReadOnly.IsChecked.Value, includeListDefinition)));
                String fileBaseClass = String.Format(@"{0}/{1}.cs",folder,ingredients.contentTypeName);
                System.IO.File.WriteAllText(fileBaseClass, sb.ToString());
                textBlockCode.Text += String.Format("Generated file {0}\n", fileBaseClass);
                sb.Remove(0, sb.Length);
                sb.Append((ingredients.buildOtherMembers()));
                String fileOtherMembers = String.Format(@"{0}/{1}.otherMembers.cs",folder,ingredients.contentTypeName);
                System.IO.File.WriteAllText(fileOtherMembers, sb.ToString());
                textBlockCode.Text += String.Format("Generated file {0}\n", fileOtherMembers);
                sb.Remove(0, sb.Length);
            }
            textBlockCode.Text += sb.ToString();
        }
       
       
        private void buttonAddToList_Click(object sender, RoutedEventArgs e)
        {
            SPList list = ((SPList)listBoxLists.SelectedValue);
            List<SPField_Extended> selectedFields = new List<SPField_Extended>();
            foreach (var f in listBoxFields.SelectedItems)
                selectedFields.Add(f as SPField_Extended);
            String contentTypeName = textBoxContentTypeName.Text;
            ContentType originalContentTypeName = listBoxContentTypes.SelectedItem as ContentType;
            String namespaceName = textBoxNamespaceName.Text;

            if (classList.Exists(c => (c.contentTypeName == contentTypeName && c.namespaceName == namespaceName)))
            {
                MessageBoxResult response = MessageBox.Show(
                        "A class with the same name and namespace already exists. You should use unique names! Do you want to overwrite existing one?", 
                        "Caution: About to overwrite existing content type!",
                        MessageBoxButton.YesNo, 
                        MessageBoxImage.Question);
                if (response == MessageBoxResult.No)
                    return;
                else
                {
                    int count = classList.RemoveAll(c => (c.contentTypeName == contentTypeName && c.namespaceName == namespaceName));
                    for (int i = 0; i < listBoxNewClasses.Items.Count; i++)
                    {
                        if (((ClassIngredients)listBoxNewClasses.Items[i]).Title == contentTypeName)
                        {
                            listBoxNewClasses.Items.RemoveAt(i);
                            // break;
                        }
                    }
                    MessageBox.Show("Duplicate removed.");
                }
            }

            ClassIngredients newClass = new ClassIngredients(list, selectedFields, contentTypeName, originalContentTypeName,namespaceName);
            classList.Add(newClass);
            listBoxNewClasses.Items.Add(newClass);
            listBoxNewClasses.MouseDoubleClick += new MouseButtonEventHandler(listBoxNewClasses_MouseDoubleClick);
            listBoxLists.SelectedIndex = 0;
            listBoxFields.Items.Clear();
            listBoxFields.IsEnabled = false;
            listBoxContentTypes.Items.Clear();
            listBoxContentTypes.IsEnabled = false;
            textBoxContentTypeName.Text = String.Empty;
            textBoxContentTypeName.IsEnabled = false;
        }

        void listBoxNewClasses_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            if (((System.Windows.Controls.ListBox)(sender)).SelectedItems.Count > 0)
            {
                DisableAllHandlers();
                ClassIngredients c = ((System.Windows.Controls.ListBox)(sender)).SelectedItems[0] as ClassIngredients;
                // site collection
                // listBoxSites.Items.Clear();
                if (!listBoxSites.Items.Contains(c.list.ParentWeb.Site.Url))
                    listBoxSites.Items.Add(c.list.ParentWeb.Site.Url);
                listBoxSites.SelectedIndex = listBoxSites.Items.IndexOf(c.list.ParentWeb.Site.Url);
                listBoxSites.Text = c.list.ParentWeb.Site.Url;
                listBoxSites.IsEnabled = true;
                OpenSitesBtn_Click(null, null);
                
                //web site
                // listBoxWebs.Items.Clear();
                if (!listBoxWebs.Items.Contains(c.list.ParentWeb.ServerRelativeUrl))
                    listBoxWebs.Items.Add(c.list.ParentWeb.ServerRelativeUrl);
                listBoxWebs.SelectedIndex = listBoxWebs.Items.IndexOf(c.list.ParentWeb.ServerRelativeUrl);
                listBoxWebs.IsEnabled = true;
                listBoxWebs_SelectionChanged(null, null);

                // list
                // listBoxLists.Items.Clear();
                // if (!listBoxLists.Items.Contains(c.list))
                //     listBoxLists.Items.Add(c.list);
                foreach (Object o in listBoxLists.Items)
                {
                    SPList l = o as SPList;
                    if (l.ID == c.list.ID)
                    {
                        listBoxLists.SelectedItem = o;
                        break;
                    }
                }
                // listBoxLists.SelectedIndex = listBoxLists.Items.IndexOf(c.list);                    
                listBoxLists.IsEnabled = true;
                listBoxLists_SelectionChanged(null, null);
                

                foreach (Object o in listBoxContentTypes.Items)
                {
                    ContentType ct = o as ContentType;
                    if (ct.Name == c.originalContentTypeName.Name)
                    {
                        listBoxContentTypes.SelectedItem = o;
                        break;
                    }
                }
                listBoxContentTypes.IsEnabled = true;
                listBoxContentTypes_SelectionChanged(null, null);
                foreach (var foo in c.selectedFields)
                {
                    SPField f = null;
                    if (foo is SPField)
                        f = (SPField)foo;
                    else if (foo is SPField_Extended)
                        f = (foo as SPField_Extended).field;

                    foreach(Object o in listBoxFields.Items)
                    {
                        if (((SPField_Extended)o).field.Title == f.Title)
                        {
                            // listBoxFields.SelectedItems.Add(((SPField_Extended)o).field);
                            listBoxFields.SelectedItems.Add(((SPField_Extended)o));
                            break;
                        }
                    }
                }
                listBoxFields.IsEnabled = true;
                textBoxContentTypeName.Text = c.contentTypeName;
                textBoxContentTypeName.IsEnabled = true;
                textBoxNamespaceName.Text = c.namespaceName;
                textBoxNamespaceName.IsEnabled = true;
            EnableAllHandlers();
        }
        }

        private void RemoveCTBtn_Click(object sender, RoutedEventArgs e)
        {
            List<ClassIngredients> toDelete = new List<ClassIngredients>();
            foreach (var c in listBoxNewClasses.SelectedItems)
            {
                toDelete.Add(c as ClassIngredients);
            }

            foreach (var c in toDelete)
            {
                listBoxNewClasses.Items.Remove(c as ClassIngredients);
                classList.RemoveAll(delete => delete.contentTypeName == (c as ClassIngredients).contentTypeName);
            }
            toDelete.Clear();
        }

        private void Save_Click(object sender, RoutedEventArgs e)
        {
            // Create OpenFileDialog
            // Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
            Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();

            // Set filter for file extension and default file extension
            dlg.DefaultExt = ".silver";
            dlg.Filter = "SPSilver documents (.silver)|*.silver";

            // Display OpenFileDialog by calling ShowDialog method
            Nullable<bool> result = dlg.ShowDialog();

            // Get the selected file name and display in a TextBox
            if (result == true)
            {
                // Open document
                string filename = dlg.FileName;
                // FileNameTextBox.Text = filename;


                StringBuilder sb = new StringBuilder();
                // String folder = DateTime.Now.ToString("yyyy.MM.dd - HH.mm");
                // DirectoryInfo dirInfo = Directory.CreateDirectory(folder);
                // textBlockCode.Text += String.Format("Created folder {0}: {1}\n", folder, dirInfo.FullName);

                System.Web.Script.Serialization.JavaScriptSerializer oSerializer =
                            new System.Web.Script.Serialization.JavaScriptSerializer();
                // JsonSerializerSettings settings = new JsonSerializerSettings { Error = (sender, args) => { if (System.Diagnostics.Debugger.IsAttached) { System.Diagnostics.Debugger.Break(); } } 
                    
                List<JsonClassIngredients> jsonClassList = new List<JsonClassIngredients>();
                try
                {
                    foreach (ClassIngredients i in listBoxNewClasses.SelectedItems)
                    {
                        jsonClassList.Add(new JsonClassIngredients(i));
                    }
                    sb.Append(oSerializer.Serialize(jsonClassList));
                }
                catch (Exception ex)
                {
                    textBlockCode.Text += (ex.ToString());
                }

                /*foreach (ClassIngredients ingredients in listBoxNewClasses.SelectedItems)
                {
                    sb.Append((ingredients.buildClassCode(classList, checkBoxIsReadOnly.IsChecked.Value)));
                    String fileBaseClass = String.Format(@"{0}/{1}.cs", folder, ingredients.contentTypeName);
                    sb.Remove(0, sb.Length);
                    sb.Append((ingredients.buildOtherMembers()));
                    String fileOtherMembers = String.Format(@"{0}/{1}.otherMembers.cs", folder, ingredients.contentTypeName);
                    System.IO.File.WriteAllText(fileOtherMembers, sb.ToString());
                    sb.Remove(0, sb.Length);
                }*/

                System.IO.File.WriteAllText(filename, sb.ToString());
                textBlockCode.Text += String.Format("Generated file {0}\n", filename);
                

            }
        }

        private void Open_Click(object sender, RoutedEventArgs e)
        {
            // Create OpenFileDialog
            Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
            // Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();

            // Set filter for file extension and default file extension
            dlg.DefaultExt = ".silver";
            dlg.Filter = "SPSilver documents (.silver)|*.silver";

            // Display OpenFileDialog by calling ShowDialog method
            Nullable<bool> result = dlg.ShowDialog();

            // Get the selected file name and display in a TextBox
            if (result == true)
            {
                // Open document
                string filename = dlg.FileName;
                // FileNameTextBox.Text = filename;
                String json = System.IO.File.ReadAllText(filename);


                System.Web.Script.Serialization.JavaScriptSerializer oSerializer =
                            new System.Web.Script.Serialization.JavaScriptSerializer();
                List<JsonClassIngredients> jsonClassList = oSerializer.Deserialize<List<JsonClassIngredients>>(json);
                
                try
                {
                    foreach (JsonClassIngredients j in jsonClassList)
                    { 
                        try
                        {
                            ClassIngredients newClass = j.getInner();
                            if (!listBoxNewClasses.Items.Contains(newClass))
                            {
                                classList.Add(newClass);
                                listBoxNewClasses.Items.Add(newClass);
                                listBoxNewClasses.MouseDoubleClick += new MouseButtonEventHandler(listBoxNewClasses_MouseDoubleClick);
                            }
                            else
                                MessageBox.Show("Class '" + newClass.Title + "' already exists. Pls remove it before importing!");
                        }
                        catch (Exception exc)
                        {
                            textBlockCode.Text += exc.ToString();
                        }
                    }
                }
                catch (Exception ex)
                {
                    textBlockCode.Text += ex.ToString();
                }
            }
        }

        void EnableAllHandlers()
        {
            isHandlersEnabled = true;
            // listBoxSites.SelectionChanged+=new SelectionChangedEventHandler(listBoxSites_SelectionChanged);
            // listBoxWebs.SelectionChanged+=new SelectionChangedEventHandler(listBoxWebs_SelectionChanged);
            // listBoxLists.SelectionChanged += new SelectionChangedEventHandler(listBoxLists_SelectionChanged);
            // listBoxContentTypes.SelectionChanged+=new SelectionChangedEventHandler(listBoxContentTypes_SelectionChanged);
        }
        Boolean isHandlersEnabled = true;

        void DisableAllHandlers()
        {
            isHandlersEnabled = false;
            // listBoxSites.SelectionChanged+=new SelectionChangedEventHandler(listBoxSites_SelectionChanged);
            // listBoxWebs.SelectionChanged -= null;// new SelectionChangedEventHandler(listBoxWebs_SelectionChanged);
            // listBoxLists.SelectionChanged -= null;//new SelectionChangedEventHandler(listBoxLists_SelectionChanged);
            // listBoxContentTypes.SelectionChanged -= null;// new SelectionChangedEventHandler(listBoxContentTypes_SelectionChanged);
        }
    }
}


public class SPField_Extended
{
    public SPField_Extended(SPField field)
    {
        this.field = field;
    }
    public String Combined_DisplayName { get { return String.Format("{0} ({1})", this.field.Title, this.field.InternalName); } }
    public SPField field { get; set; }
}